package cn.wolfcode.p2p.base.service.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import cn.wolfcode.base.QueryObject;
import cn.wolfcode.p2p.base.domain.Account;
import cn.wolfcode.p2p.base.domain.IpLog;
import cn.wolfcode.p2p.base.domain.LoginInfo;
import cn.wolfcode.p2p.base.domain.UserInfo;
import cn.wolfcode.p2p.base.exception.CustomerException;
import cn.wolfcode.p2p.base.mapper.AccountMapper;
import cn.wolfcode.p2p.base.mapper.IpLogMapper;
import cn.wolfcode.p2p.base.mapper.LoginInfoMapper;
import cn.wolfcode.p2p.base.mapper.UserInfoMapper;
import cn.wolfcode.p2p.base.query.IpLogQuery;
import cn.wolfcode.p2p.base.service.IIpLogService;
import cn.wolfcode.p2p.base.service.ILoginInfoService;
import cn.wolfcode.p2p.base.service.IVerifyCodeService;
import cn.wolfcode.p2p.base.util.AssertUtil;
import cn.wolfcode.p2p.base.util.Constant;
import cn.wolfcode.p2p.base.util.LoginInfoContext;
import cn.wolfcode.p2p.base.util.MD5;

@Service
@Transactional
public class LoginInfoServiceImpl implements ILoginInfoService {
    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private IVerifyCodeService verifyCodeService;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private IpLogMapper ipLogMapper;
    @Autowired
    private IIpLogService ipLogService;

    @Transactional(readOnly = true)
    public PageInfo<LoginInfo> query(QueryObject qo) {
        PageHelper.startPage(qo.getCurrentPage(), qo.getPageSize());
        List<LoginInfo> list = loginInfoMapper.selectList(qo);
        return new PageInfo<LoginInfo>(list);
    }

    public void register(String username, String password, String verifyCode) {
        // 后台校验
        // 号码不能为空
        // 是否是号码格式
        // 密码是否为 4-16 位
        AssertUtil.INSTANCE
                .isNotEmpty(username, "手机号码不能为空")
                .isPhoneNumber(username, "手机号码格式错误")
                .lenghtIn(password, 4, 16, "密码在4~16位之间");

        // 判断验证码是否一致
        verifyCodeService.checkCode(username, verifyCode);

        // 用户排重, 判断是否存在相同的用户名
        AssertUtil.INSTANCE.isFalse(this.checkUsernameExist(username), "亲, 该号码已被注册, 请重新选择");

        // 注册
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setUsername(username)
                .setPassword(MD5.encode(password))
                .setState(LoginInfo.STATE_NORMAL)
                .setUserType(LoginInfo.TYPE_USER);
        ;
        loginInfoMapper.insert(loginInfo);

        // 基本信息, 账户信息  主键关联

        UserInfo userInfo = new UserInfo();
        userInfo.setId(loginInfo.getId());
        // 设置手机号码
        userInfo.setPhoneNumber(loginInfo.getUsername());
        userInfoMapper.insert(userInfo);

        Account account = new Account();
        account.setId(loginInfo.getId());
        // 将登陆密码设置为支付密码
        account.setTradePassword(loginInfo.getPassword());
        accountMapper.insert(account);

    }

    public boolean checkUsernameExist(String username) {
        int count = loginInfoMapper.selectCountByUsername(username);
        return count > 0;
    }

    public boolean getUsernameExist(String username) {

        return this.checkUsernameExist(username);
    }

    public LoginInfo login(String username, String password, Integer userType) {

        LoginInfo loginInfo = loginInfoMapper.selectByUsernameAndPassword(username, MD5.encode(password), userType);


        // 被锁定就不需要保存登录日志, 直接抛异常
        if (loginInfo != null && loginInfo.getState() == LoginInfo.STATE_LOCK) {
            throw new CustomerException("该账户已锁定, 请联系客服...");
        }

        // 记录登录日志, 当天连续输入5次错误密码就马上锁定账户, 登录成功则次数清零
        IpLog ipLog = new IpLog();

        // 设置当前登录的ip地址
        // 设置登录时间
        // 设置用户名
        // 设置登录状态
        // 设置用户类型
        ipLog.setIp(LoginInfoContext
                .getCurrentRequestIp())
                .setLoginTime(new Date())
                .setUsername(username)
                .setState(loginInfo != null ? IpLog.STATE_SUCCESS : IpLog.STATE_FAILING)
                .setUserType(userType);

        // 只有前台用户登录才做锁定
        if (userType == LoginInfo.TYPE_USER){
            // 如果当初登录失败, 根据当天日期查询前4次登录日期, 如果都为失败, 则将账户设为锁定
            if (ipLog.getState() == IpLog.STATE_FAILING){
                // 获取当天日期
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String date = sdf.format( new Date());

                // 按时间倒序, 查询前4次登录日志
                IpLogQuery qo = new IpLogQuery();
                qo.setCurrentDate(date);
                qo.setPageSize(4);
                // 按时间倒排序
                qo.setGroupType("login_time desc");

                PageInfo<IpLog> query = ipLogService.query(qo);

                // 如果列表长度大于0
                if (query.getList().size() == 4){
                    // 定义一个变量, 如果查询出来的状态有登录成功 设为1
                    int number = 0;
                    for (IpLog il : query.getList()){
                        if (il.getState() == IpLog.STATE_SUCCESS){
                            number = 1;
                            break;
                        }
                    }
                    if (number == 0){
                        // 将该账户的状态设为锁定
                        loginInfoMapper.updateState(new LoginInfo().setUsername(username).setState(LoginInfo.STATE_LOCK));
                    }
                }

            }
        }
        ipLogMapper.insert(ipLog);

        // 将用户对象存储进session中
        LoginInfoContext.setCurrentLoginInfo(loginInfo);
        return loginInfo;
    }

    public void initAdmin() {
        // 查询用户类型为 1 的 用户个数
        int rows = loginInfoMapper.selectCountByUserType(LoginInfo.TYPE_MANAGER);

        if (rows == 0){
            // 创建一个管理员
            LoginInfo admin = new LoginInfo();
            admin.setUsername(Constant.DEFAULT_ADMIN_USERNAME)
                    .setPassword(MD5.encode(Constant.DEFAULT_ADMIN_PASSWORD))
                    .setUserType(LoginInfo.TYPE_MANAGER)
                    .setState(LoginInfo.STATE_NORMAL);

            loginInfoMapper.insert(admin);
        }
    }

    public LoginInfo checkUsername(String username) {
        return loginInfoMapper.selectByUsername(username);
    }

    public List<LoginInfo> listCustomServices() {
        return loginInfoMapper.selectCustomServices();
    }
}
